using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using FCS;
using Applications;

namespace Func
{
    class Program : Functional
    {
        class Animal
        {
        }

        class Mammal : Animal
        {
        }

        class Dog : Mammal
        {
        }

        private Dog Ret(Animal a)
        {
            return new Dog();
        }
        //string IsNullEager(string first, string second)
        //{
        //    return first != null ? first : second;
        //}

        //string IsNullLazy(Func<string> first, Func<string> second)
        //{
        //    return first() != null ? first() : second();
        //}

        //string IsNullLazy(Func<string> first, Func<string> second)
        //{
        //    return first() ?? second();
        //}

        //string longTimeOperation()
        //{
        //    return "x";
        //}

        private void Show()
        {
            //// Parameters are passed using lambda expressions
            //string val = null;
            //// Method call
            //IsNullEager(val, longTimeOperation());
            //IsNullLazy(() => val, () => longTimeOperation());

            var infList = IntList(1, 200);

            Output("Filter & Map & other operations:");
            Output(Filter(e => e % 4 == 0, Map(v => v * 2, infList)));

            Output("Head & Tail & Cons:");
            Output(Head(infList));
            Output(Tail(infList));
            Output(Cons(HeadValue(infList), Tail(infList)));

            Output("LINQ integration:");
            var vv = from a
                     in infList
                     where a < 4
                     select a;
            Output(vv);

            Output("List of strings:");
            Output(Cons("a", Cons("b", null)));
            Output("List from Array:");
            Output(ListFromArray(new int[] { 1, 2, 3, 4, 5 }));

            Output("Quicksort:");
            var rnd = new Random();
            Output(new QuickSort(Map(a => rnd.Next(100), IntList(1, 100))) as IFunList<int>);

            Output("Fibonacci:");
            Perform(v => Output(new Fibonacci(v).Value), IntList(0, 10));
            Output(Map(v => new Fibonacci(v).Value, IntList(0, 25)));

            Output("Factorial:");
            Output(new Factorial(4).Value);

            Output("Primes:");
            Output(new Primes(IntList(2, 200)) as IFunList<int>);
            Output("Number of Primes from 2 to 5000:");
            Output(new Primes(IntList(2, 5000)).Count());

            Output("IsContain:");
            Output(new IsContain<int>(2, IntList(1, 5)).Value);
            Output(new IsContain<int>(1, IntList(2, 5)).Value);

            Output("Curry (Even):");
            Output(Even()(2));
            Output(Even()(3));

            Output("First 5 Primes:");
            Output(Take(5, new Primes(IntList(2, 100))));
            Output("Queens:");
            var qs = new Queens(8);
            foreach (var q in qs)
            {
                foreach (var a in q)
                {
                    Console.Write(a);
                }
                Console.WriteLine();
            }

            Output(Foldl((a, b) => a + b, 0, IntList(1, 100)));
            Output(Foldr((a, b) => a * b, 1, IntList(1, 10)));

            Output(Foldl((a, b) => (int)Math.Pow(a, b), 2, IntList(2, 3)));
            Output(Foldr((a, b) => (int)Math.Pow(a, b), 2, IntList(2, 3)));

            Measure(() => Console.WriteLine(new Queens(12).Count()));
            Measure(() => {for(int i = 0;i < 200;i++) new Queens(8).Count();});

            Measure(() =>
            {
                Console.WriteLine(new Primes(IntList(2, 20001)).Count());
                Console.WriteLine(new Primes(IntList(2, 20001)).Count());
                Console.WriteLine(new Primes(IntList(2, 20001)).Count());
                Console.WriteLine(new Primes(IntList(2, 20001)).Count());
                Console.WriteLine(new Primes(IntList(2, 20001)).Count());
            });

            Map(a => Ret(a), Cons<Mammal>(new Mammal(), null));
        }

        static void Measure(Action f)
        {
            DateTime start = DateTime.Now;
            f();
            Console.WriteLine(DateTime.Now - start);
        }

        static void Main(string[] args)
        {
            new Program().Show();
        }
    }
}

